using System.Data;
using Chaotic.DataBase.DataAccess;
using Chaotic.DataBase.DBAccessLibrary.DBAccessLibrary;
using Chaotic.DataBase.DBAccessLibrary.Interface;
using Chaotic.DataBase.DBAccessLibrary.Model;

namespace Chaotic.DataBase.DBAccessLibrary.Grammar;

internal class Db2Grammar : DBGrammar, IGrammar, ILocalGrammar
{
	public string GetChTableSql
	{
		get
		{
			if (string.IsNullOrEmpty(_xml.ChDescription))
			{
				return "SELECT TABLENAME,CHINESETABLENAME as CHINATABLENAME,FIELDNAME as COLUMNNAME,CHINESENAME as CHINACOLUMNNAME FROM T_FIELD_DICTIONARY order by TABLENAME";
			}
			return _xml.ChDescription;
		}
	}

	public string? IsExistChTableSql
	{
		get
		{
			string? result = string.Empty;
			if (string.IsNullOrEmpty(_xml.ChDescription))
			{
				result = "select name from sysibm.systables where name='T_FIELD_DICTIONARY'";
			}
			return result;
		}
	}

	public Db2Grammar(ConnectionModel? connect)
		: base(connect)
	{
	}

	private string? GetTypeFilter(FieldEntity? field, string sql)
	{
		string? text = field.TypeName;
		int.TryParse(field.Length, out var result);
		string? text2 = field.Length;
		string text3 = field.TypeName.ToUpper();
		string? text4 = $"'{field.DefaultValue}'";
		if (text3 == "VARCHAR2" || text3 == "VARCHAR")
		{
			text = "VARCHAR";
			text2 = $"({field.Length})";
		}
		if (text3 == "INTEGER" || text3 == "SMALLINT")
		{
			text2 = "";
			text4 = field.DefaultValue;
		}
		if (text3 == "NUMBER" && result < 9)
		{
			text = "INTEGER";
			text2 = "";
			text4 = field.DefaultValue;
		}
		else if (text3 == "NUMBER" && result >= 9)
		{
			text = "DECIMAL";
			text2 = "(18,2)";
			text4 = field.DefaultValue;
		}
		if (text3 == "TIMESTAMP" || text3 == "DATE")
		{
			text2 = "";
		}
		return string.Format(sql, field.TableName, field.Name, text, text2, text4);
	}

	public string? AddColumn(FieldEntity? field)
	{
		string text = "ALTER TABLE {0} ADD COLUMN {1} {2}{3}";
		if (!field.IsNull)
		{
			text += " Not Null";
		}
		if (!string.IsNullOrEmpty(field.DefaultValue))
		{
			text += " WITH DEFAULT {4}";
		}
		return GetTypeFilter(field, text);
	}

	public IEnumerable<string?> EditColumn(FieldEntity? field)
	{
		List<string?> list = new List<string?>();
		if (field.IsChange((FieldEntity o) => o.Length))
		{
			int num = Convert.ToInt32(field.GetNoChangeValue((FieldEntity o) => o.Length).ToString());
			if (Convert.ToInt32(field.Length) > num)
			{
				list.Add(GetTypeFilter(field, "ALTER TABLE {0} ALTER COLUMN {1} SET DATA TYPE {2}{3}"));
			}
		}
		if (field.IsChange((FieldEntity o) => o.DefaultValue))
		{
			if (!string.IsNullOrEmpty(field.DefaultValue))
			{
				list.Add(GetTypeFilter(field, "ALTER TABLE {0} ALTER COLUMN {1} SET WITH DEFAULT {4}"));
			}
			else
			{
				list.Add(GetTypeFilter(field, "ALTER TABLE {0} ALTER COLUMN {1} DROP DEFAULT"));
			}
		}
		return list;
	}

	public IEnumerable<string?> RemoveColumn(FieldEntity field)
	{
		List<string?> list = new List<string?>();
		list.Add($"ALTER TABLE {field.TableName} DROP COLUMN {field.TransName}");
		return list;
	}

	public IEnumerable<string?> EditPrimary(TableEntity table)
	{
		List<string?> list = new List<string?>();
		string text = table.PrimaryKeyName;
		string[] array = (from o in table.FileNodes
			where o.IsPrimaryKey
			select o.Name).ToArray();
		if (array.Length > 0)
		{
			if (!string.IsNullOrEmpty(text))
			{
				string? item = $"alter table {table.Name} drop constraint {text} ";
				list.Add(item);
			}
			else
			{
				text = "PK" + array[0];
			}
			list.Add(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY({2})", table.Name, text, string.Join(",", array)));
		}
		return list;
	}

	public string? SelectTop(TableEntity table, int count)
	{
		return $"SELECT * FROM {table.TransName} FETCH FIRST {count} ROWS  ONLY";
	}

	public string AppendTabText(string text)
	{
		string text2;
		if ((text2 = text.ToUpper().Trim()) != null && text2 == "EI")
		{
			return "SELECT COLNAME FROM SYSCAT.COLUMNS WHERE  TABNAME= (SELECT TABNAME FROM SYSCAT.TABLES WHERE TBSPACEID = {0} AND TABLEID = {1}) AND COLNO = {2}";
		}
		return TabText(text);
	}

	public string GetErrorInfo(string errorMsg)
	{
		if (SysCache.DBConnection.ConnectType == DatabaseType.DB2)
		{
			try
			{
				if (errorMsg.Contains("TBSPACEID=") && errorMsg.Contains("TABLEID=") && errorMsg.Contains("COLNO="))
				{
					int num = errorMsg.IndexOf("TBSPACEID=", StringComparison.Ordinal) + "TBSPACEID=".Length;
					string arg = errorMsg.Substring(num, errorMsg.IndexOf(',', num) - num);
					num = errorMsg.IndexOf("TABLEID=", StringComparison.Ordinal) + "TABLEID=".Length;
					string arg2 = errorMsg.Substring(num, errorMsg.IndexOf(',', num) - num);
					num = errorMsg.IndexOf("COLNO=", StringComparison.Ordinal) + "COLNO=".Length;
					string arg3 = errorMsg.Substring(num, errorMsg.IndexOf('"', num) - num);
					return $"SELECT COLNAME FROM SYSCAT.COLUMNS WHERE  TABNAME= (SELECT TABNAME FROM SYSCAT.TABLES WHERE TBSPACEID = {arg} AND TABLEID = {arg2}) AND COLNO = {arg3}";
				}
			}
			catch
			{
			}
		}
		return string.Empty;
	}

	public string? GetProcParamInfo(ProcEntity entity)
	{
		if (entity == null)
		{
			return string.Empty;
		}
		string arg;
		if (entity.ChildNodes.Count > 0)
		{
			List<string> list = new List<string>();
			foreach (ProcParamEntity? childNode in entity.ChildNodes)
			{
				if (childNode.Status == "IN")
				{
					list.Add($"{Environment.NewLine}[{childNode.Name}({childNode.TypeName})]");
				}
				else
				{
					list.Add($"{Environment.NewLine}[{childNode.Name}({childNode.TypeName})-OUT]");
				}
			}
			arg = string.Format("({0})", string.Join(",", list.ToArray()));
		}
		else
		{
			arg = "()";
		}
		return string.Format("{0} {1}{2}", "CALL", entity.Name, arg);
	}

	protected override string GetProcName(string sql, out string paramStr)
	{
		paramStr = string.Empty;
		if (sql.StartsWith("CALL ", StringComparison.CurrentCultureIgnoreCase))
		{
			int num = sql.IndexOf("CALL ", StringComparison.CurrentCultureIgnoreCase) + 5;
			int num2 = sql.IndexOf("(", StringComparison.Ordinal);
			paramStr = sql.Substring(num2 + 1, sql.LastIndexOf(")", StringComparison.Ordinal) - num2 - 1);
			return sql.Substring(num, num2 - num);
		}
		return string.Empty;
	}

	public string GetPageingSql(string sql, decimal index, decimal count)
	{
		string format = string.Format("SELECT tab.* FROM (SELECT {{0}} ROWNUMBER,t.* FROM ({0}{{1}}{0}) t) tab  WHERE tab.ROWNUMBER >= {1} and tab.ROWNUMBER < {2}", Environment.NewLine, index, count);
		return string.Format(format, "ROW_NUMBER() OVER()", sql);
	}

	protected override string GetRowNumUpdate(string tableName, string where, string column, string? rownumber)
	{
		return string.Format("UPDATE ({0}) T1 SET {1} WHERE T1.ROWNUMBER={2}", string.Format("{0} {1}", string.Format("SELECT ROW_NUMBER() OVER() ROWNUMBER,{0}.* FROM {0}", tableName), where), column, rownumber);
	}

	protected override string GetRowNumDelete(string tableName, string where, string? rownumber)
	{
		return string.Format("DELETE FROM ({0}) T1 WHERE T1.ROWNUMBER={1}", string.Format("{0} {1}", string.Format("SELECT ROW_NUMBER() OVER() ROWNUMBER,{0}.* FROM {0}", tableName), where), rownumber);
	}

	public DatabaseType GetConnectionStr(out string connectStr)
	{
		connectStr = "Database={0};user id={1};password={2};server={3}";
		connectStr = string.Format(connectStr, _connect.DataBase, _connect.UserID, _connect.PassWord, _connect.Server);
		return DatabaseType.DB2;
	}

	public override void SaveChange(TableEntity table, IList<FieldEntity?> newList, Action<string, int> WriteLog, Func<string, bool>? showMsg)
	{
		List<FieldEntity?> list = new List<FieldEntity?>();
		List<FieldEntity?> list2 = new List<FieldEntity?>();
		bool flag = false;
		bool flag2 = false;
		try
		{
			foreach (FieldEntity? @new in newList)
			{
				if (@new.Status == EditStatus.Delete)
				{
					foreach (string? item in @new.RemoveColumnSql)
					{
						WriteLog(item, 0);
						DBOperatorFactory.GetOperator.ExecNonQuery(item, SysCache.DBConnection, null, TransactionType.Transaction);
					}
					list.Add(@new);
				}
				else if (@new.Status == EditStatus.Add)
				{
					string? addColumnSql = @new.AddColumnSql;
					WriteLog(addColumnSql, 0);
					DBOperatorFactory.GetOperator.ExecNonQuery(addColumnSql, SysCache.DBConnection, null, TransactionType.Transaction);
					list2.Add(@new);
				}
				else if (@new.Status == EditStatus.Modify && !flag)
				{
					if (@new.IsChange((FieldEntity o) => o.Length) || @new.IsChange((FieldEntity o) => o.DefaultValue))
					{
						IEnumerable<string?> enumerable = DBOperatorFactory.GetGrammar(SysCache.DBConnection).EditColumn(@new);
						if (!enumerable.Any())
						{
							flag = true;
						}
						else
						{
							foreach (string? item2 in enumerable)
							{
								WriteLog(item2, 0);
								DBOperatorFactory.GetOperator.ExecNonQuery(item2, SysCache.DBConnection, null, TransactionType.Transaction);
							}
						}
					}
					else
					{
						flag = true;
					}
				}
				if (!flag2 && @new.IsChange((o) => o.IsPrimaryKey))
				{
					flag2 = true;
				}
				if (@new.Status != 0)
				{
					DBOperatorFactory.GetOperator.SaveDescription(table, @new, string.Empty, isnewTable: false, TransactionType.Transaction);
				}
			}
			if (flag2)
			{
				foreach (string? item3 in table.AddPrimarySql)
				{
					WriteLog(item3, 0);
					DBOperatorFactory.GetOperator.ExecNonQuery(item3, SysCache.DBConnection, null, TransactionType.Transaction);
				}
			}
			if (flag)
			{
				if (showMsg != null && !showMsg("该操作会造成重建表结构，是否继续?"))
				{
					throw new Exception("取消操作");
				}
				List<DBParam> list3 = new List<DBParam>();
				Dictionary<string, object> outdic = new Dictionary<string, object>();
				list3.Add(new DBParam
				{
					Name = "EXEC_MODE",
					ParamType = 1,
					TypeName = "VARCHAR",
					Value = "APPLY_CONTINUE_ON_ERROR"
				});
                if (SysCache.DBConnection != null)
                {
                    list3.Add(new DBParam
                    {
                        Name = "SQL_STMT",
                        ParamType = 1,
                        TypeName = "VARCHAR",
                        Value = GetCreateTable(SysCache.DBConnection.ConnectType, table, isAddPrimary: false) +
                                " IN USERSPACE1"
                    });
                    list3.Add(new DBParam
                    {
                        Name = "ALITER_ID",
                        ParamType = 1,
                        TypeName = "INTEGER",
                        Value = -1
                    });
                    list3.Add(new DBParam
                    {
                        Name = "MSG",
                        ParamType = 2,
                        TypeName = "VARCHAR",
                        Value = "?"
                    });
                    WriteLog("调用存储过程-->ALTOBJ", 0);
                    DBOperatorFactory.GetOperator.ExecProc("ALTOBJ", list3, out outdic, SysCache.DBConnection,
                        TransactionType.Transaction);
                    WriteLog("返回-->" + outdic["MSG"], 0);
                    DataSet? dataSet = DBOperatorFactory.GetOperator.ExecSqlToDS(outdic["MSG"].ToString());
                    DataRow dataRow = dataSet.Tables[0].AsEnumerable().FirstOrDefault((o) =>
                        o.Field<string>("OBJ_NAME") != table.Name &&
                        o.Field<string>("OBJ_NAME").EndsWith("_EXCEPTION"));
                    string? text = dataRow?["OBJ_NAME"].ToString();
                    WriteLog("删除表-->" + text, 0);
                    DBOperatorFactory.GetOperator.ExecNonQuery("DROP TABLE " + text, SysCache.DBConnection, null,
                        TransactionType.Transaction);
                    if (text != null)
                    {
                        int num = text.LastIndexOf("_EXCEPTION", StringComparison.Ordinal);
                        text = text.Remove(num, text.Length - num);
                    }

                    WriteLog("删除表-->" + text, 0);
                    DBOperatorFactory.GetOperator.ExecNonQuery("DROP TABLE " + text, SysCache.DBConnection, null,
                        TransactionType.Transaction);
                }
            }
			DBOperatorFactory.GetOperator.CommitTransaction(SysCache.DBConnection);
			table.Commit();
			list.ForEach(delegate(FieldEntity? o)
			{
				newList.Remove(o);
				table.Remove(o);
			});
			list2.ForEach(delegate(FieldEntity? o)
			{
				o.Status = EditStatus.UnChange;
				table.Add(o);
			});
			foreach (FieldEntity? item4 in list)
			{
				newList.Remove(item4);
			}
			WriteLog("提交成功", 0);
		}
		catch (Exception ex)
		{
			DBOperatorFactory.GetOperator.RollbackTransaction(SysCache.DBConnection);
			table.RollBack();
			if (flag)
			{
				WriteLog("基础数据回滚成功，但存储过程无法回滚，可能会产生2张临时表，请手动删除。异常详细:" + ex.Message, 1);
			}
			else
			{
				WriteLog("回滚成功.异常详细:" + ex.Message, 1);
			}
			throw;
		}
	}
}
